Android

안드로이드 5기 2017년 강의 정리 5 (오준석의 생존코딩)

 

https://www.youtube.com/watch?v=bC_YZkSBTl8&list=PLxTmPHxRH3VWSF7kMcsIaTglWUJZpWeQ9&index=105

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki

MyFirstAndroidApp5ki-master.zip

 

35일차 36일차 뮤직플레이어

37일차 Parcelable

37일차 Custom Toast, 40일차 다이얼로그 액티비티

38일차 오버워치 앱 리뷰

40일차 다이얼로그 액티비티

41일차 커스텀 뷰

42일차 DataBinding 라이브러리

42일차 45일차 XML파싱 뉴스앱

 


 

35일차 36일차 뮤직플레이어

 

# MediaPlayer overview (android developer)
https://developer.android.com/guide/topics/media/mediaplayer#java

 

# MusicPlayerActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/MusicPlayerActivity.java

# activity_music_player.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_music_player.xml

# MusicService.java

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/services/MusicService.java

# PlayerFragment.java

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/fragments/PlayerFragment.java

# music_player.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/music_player.xml

# SongFragment.java

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/fragments/SongFragment.java

# fragment_song.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/fragment_song.xml

# MusicControllerFragment.java

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/fragments/MusicControllerFragment.java

# music_controller.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/music_controller.xml

# ListViewFragment.java

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/fragments/ListViewFragment.java

# fragment_list_view.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/fragment_list_view.xml

# fragment_song.xml

https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/fragment_song.xml

 

 


 

37일차 Parcelable

 

# Parcelable (android developer)
https://developer.android.com/reference/android/os/Parcelable

# Parcelables and Bundles (android developer)
https://developer.android.com/guide/components/activities/parcelables-and-bundles#java

 

# Android Parcelable code generator 플러그인 설치

  1. File – Settings – Plugins – Android Parcelable code generator 설치

 

# A typical implementation of Parcelable is:

 public class MyParcelable implements Parcelable {
     private int mData;

     public int describeContents() {
         return 0;
     }

     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
     }

     public static final Parcelable.Creator<MyParcelable> CREATOR
             = new Parcelable.Creator<MyParcelable>() {
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }

         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };

     private MyParcelable(Parcel in) {
         mData = in.readInt();
     }
 }

 


 

37일차 Custom Toast, 40일차 다이얼로그 액티비티

 

# CustomDesignActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/CustomDesignActivity.java

# MyUtils.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/utils/MyUtils.java

# activity_custom_design.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_custom_design.xml

# background_toast.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/drawable/background_toast.xml

# activity_dialog_theme.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_dialog_theme.xml

 

# CircleImageView
https://github.com/hdodenhof/CircleImageView

 

public class CustomDesignActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_design);
    }

    public void showToast(View view) {
        MyUtils.makeText(this, "나만의 토스트 ㅋㅋㅋ", Toast.LENGTH_SHORT).show();
    }

    public void showDialogActivity(View view) {
        Intent intent = new Intent(this, DialogThemeActivity.class);
        intent.putExtra("data", "ㅋㅋㅋㅋㅋㅋ");
        intent.putExtra("image", "ㅋㅋㅋㅋㅋㅋ");
        startActivity(intent);
    }

    public void showAlertDialog(View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this,
                R.style.Theme_AppCompat_Dialog);
        View layout = getLayoutInflater().inflate(R.layout.activity_dialog_theme, null, false);
        ((TextView) layout.findViewById(R.id.text_view)).setText("ㅋㅋㅋㅋㅋㅋ");
        ((ImageView) layout.findViewById(R.id.image_view)).setImageResource(R.drawable.man);
        builder.setView(layout);
        builder.show();
    }
}

 

 

public class MyUtils {
    public static int sum(int a, int b) {
        return a + b;
    }

    public static Toast makeText(Context context, CharSequence message, int duration) {
        Toast result = new Toast(context);

        View v = LayoutInflater.from(context).inflate(R.layout.custom_toast, null);
        TextView tv = (TextView) v.findViewById(R.id.message_text);
        tv.setText(message);

        result.setView(v);

        result.setDuration(duration);
        result.setGravity(Gravity.CENTER_HORIZONTAL,
                0, -300);
        return result;
    }

    public static String getRealPath(Context context, Uri uri) {
        String strDocId = DocumentsContract.getDocumentId(uri);
        String[] strSplittedDocId = strDocId.split(":");
        String strId = strSplittedDocId[strSplittedDocId.length - 1];

        Cursor crsCursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI ,
                new String[] {MediaStore.MediaColumns.DATA} ,
                "_id=?",
                new String []{strId},
                null
        );
        crsCursor.moveToFirst();
        String filePath = crsCursor.getString(0);

        return filePath;
    }
}

 

# drawable/background_toast.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <stroke
        android:width="4dp"
        android:color="#e040fb" />

    <corners android:radius="16dp" />

    <solid android:color="#e1bee7" />

</shape>

 

# 다이얼로그 테마 적용 (AndroidManifest.xml)

<activity android:name=".activities.DialogThemeActivity" android:theme="@style/Theme.AppCompat.Dialog" />

 

# android_dialog_theme.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:text="aaaa"
        android:textSize="24sp"
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</androidx.constraintlayout.widget.ConstraintLayout>

 


 

38일차 오버워치 앱 리뷰

 

# Parceler
https://github.com/johncarl81/parceler

 

 

# Shrink your resources
https://developer.android.com/studio/build/shrink-code#shrink-resources

android {
    ...
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

 

# How to create a release signed apk file using Gradle?
https://stackoverflow.com/questions/18328730/how-to-create-a-release-signed-apk-file-using-gradle

 

# cmd 로 apk 파일 만들기
gradlew installRelease

 


 

41일차 커스텀 뷰

 

# JoystickView.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/views/JoystickView.java

 

public class JoystickView extends View {
    private Paint mBackgroundPaint = new Paint();
    private Paint mJoystickPaint = new Paint();
    private float mX = 200;   // 0 ~ 400
    private float mY = 200;   // 0 ~ 400

    // 코드로 생성할 때
    public JoystickView(Context context) {
        this(context, null);
    }

    // XML에 삽입할 때
    public JoystickView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mBackgroundPaint.setColor(Color.BLACK);
        mBackgroundPaint.setStyle(Paint.Style.STROKE);

        mJoystickPaint.setColor(Color.RED);
    }

    // View의 모양을 그리는 곳
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawCircle(200, 200, 200, mBackgroundPaint);

        canvas.drawCircle(mX, mY, 100, mJoystickPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                final int historySize = event.getHistorySize();
                final int pointerCount = event.getPointerCount();
                for (int h = 0; h < historySize; h++) {
                    for (int p = 0; p < pointerCount; p++) {
                        mX = event.getHistoricalX(p, h);
                        mY = event.getHistoricalY(p, h);
                        if (Math.sqrt(Math.pow(200 - mX, 2) + Math.pow(200 - mY, 2)) > 100) {
                            return true;
                        }
                        // onDraw() 를 호출
                        invalidate();
                    }
                }

                break;
            case MotionEvent.ACTION_UP:
                mX = 200;
                mY = 200;
                invalidate();
                break;
        }

        return true;
    }

    // 크기 결정
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    // 위치
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }
}

 


 

42일차 DataBinding 라이브러리

 

# DataBindingActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/DataBindingActivity.java

# activity_data_binding.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_data_binding.xml

 

public class DataBindingActivity extends AppCompatActivity implements View.OnClickListener {

    private ActivityDataBindingBinding mBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mBinding = DataBindingUtil.setContentView(this,
                R.layout.activity_data_binding);

        mBinding.button10.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

    }

    public static class MyFragment extends Fragment {

        private FragmentDataBindingBinding mBinding;

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            mBinding = DataBindingUtil.inflate(inflater,
                    R.layout.fragment_data_binding,
                    container,
                    false);
            return mBinding.getRoot();
        }
    }
}

 

# activity_data_binding.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.myapplication.activities.DataBindingActivity">


        <TextView
            android:id="@+id/textView4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/name_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView6"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView7"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView8"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView9"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView10"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView11"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView12"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <TextView
            android:id="@+id/textView13"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />

        <Button
            android:id="@+id/button10"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Spinner
            android:id="@+id/spinner2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <SeekBar
            android:id="@+id/seekBar2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <CheckBox
            android:id="@+id/checkBox"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="CheckBox" />
    </LinearLayout>
</layout>

 

 


 

42일차 XML파싱 뉴스앱

 

NewsXMLActivity.java
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/java/com/example/myapplication/activities/NewsXMLActivity.java

 

# activity_news_xml.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/activity_news_xml.xml

 

# item_news.xml
https://github.com/suwonsmartapp/MyFirstAndroidApp5ki/blob/master/app/src/main/res/layout/item_news.xml

 

# Parse XML data (android developer)
https://developer.android.com/training/basics/network-ops/xml#java

 

# Android Studio Java XmlPullParser how to get only certain tag values (stackoverflow.com)
https://stackoverflow.com/questions/48290357/android-studio-java-xmlpullparser-how-to-get-only-certain-tag-values

 

 

import android.app.ListActivity;
import android.os.Bundle;
import android.util.Xml;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import androidx.databinding.DataBindingUtil;

import com.example.myfirstappapplication.databinding.ItemNewsBinding;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class NewsXMLActivity extends ListActivity {

    private OkHttpClient mClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mClient = new OkHttpClient();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Request request = new Request.Builder()
                            .url("https://news.google.co.kr/news?cf=all&hl=ko&pz=1&ned=kr&output=rss")
                            .build();
                    Response response = null;
                    response = mClient.newCall(request).execute();
                    final String xml = response.body().string();

                    // 파싱
                    final List<News> data = parse(xml);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // 어댑터 꽂아주기
                            NewsAdapter adapter = new NewsAdapter(data);
                            setListAdapter(adapter);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private List<News> parse(String xml) {
        try {
            return new NewsParser().parse(xml);
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static class News {
        String title;
        String link;
        String pubDate;
        String source;

        @Override
        public String toString() {
            final StringBuffer sb = new StringBuffer("News{");
            sb.append("title='").append(title).append('\'');
            sb.append(", link='").append(link).append('\'');
            sb.append(", pubDate='").append(pubDate).append('\'');
            sb.append(", category='").append(source).append('\'');
            sb.append('}');
            return sb.toString();
        }
    }

    private static class NewsAdapter extends BaseAdapter {

        private List<News> mData;
        private ItemNewsBinding mmBinding;

        public NewsAdapter(List<News> data) {
            mData = data;
        }

        @Override
        public int getCount() {
            return mData.size();
        }

        @Override
        public Object getItem(int position) {
            return mData.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                mmBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
                        R.layout.item_news, parent, false);

                convertView = mmBinding.getRoot();

                holder = new ViewHolder();

                holder.titleTextView = mmBinding.titleText;
                holder.dateTextView = mmBinding.dateText;
                holder.sourceTextView = mmBinding.sourceText;
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            News news = (News) getItem(position);
            holder.titleTextView.setText(news.title);
            holder.dateTextView.setText(news.pubDate);
            holder.sourceTextView.setText(news.source);

            return convertView;
        }
    }

    private static class ViewHolder {
        TextView titleTextView;
        TextView dateTextView;
        TextView sourceTextView;
    }

    private static class NewsParser {
        public List<News> parse(String xml) throws XmlPullParserException, IOException {

            List<News> newsList = new ArrayList<>();
            News news = null;
            String text = "";
            boolean isItem = false;

            XmlPullParser parser = Xml.newPullParser();

            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);

            parser.setInput(new StringReader(xml));
            int eventType = parser.getEventType();
            while(eventType != XmlPullParser.END_DOCUMENT) {
                String tagName = parser.getName();

                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if (tagName.equals("item")) {
                            news = new News();
                            isItem = true;
                        }
                        break;

                    case XmlPullParser.TEXT:
                        if (isItem) {
                            text = parser.getText();
                        }
                        break;

                    case XmlPullParser.END_TAG:
                        if (isItem) {
                            if (tagName.equals("item")) {
                                newsList.add(news);
                                isItem = false;
                            } else if (tagName.equals("title")) {
                                news.title = text;
                            } else if (tagName.equals("link")) {
                                news.link = text;
                            } else if (tagName.equals("source")) {
                                news.source = text;
                            } else if (tagName.equals("pubDate")) {
                                news.pubDate = text;
                            }
                        }
                        break;
                    default:
                }

                eventType = parser.next();
            }

            return newsList;
        }
    }
}

 

# item_news_xml.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</androidx.constraintlayout.widget.ConstraintLayout>

 

# item_news.xml

<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            android:text="TextView"
            android:textSize="18sp"
            app:layout_constraintBottom_toTopOf="@+id/date_text"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/date_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:text="TextView"
            app:layout_constraintEnd_toStartOf="@+id/source_text"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/title_text" />

        <TextView
            android:id="@+id/source_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="TextView"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/date_text"
            app:layout_constraintTop_toBottomOf="@+id/title_text" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

 

 

Related posts

Leave a Comment